﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using XXF.BaseService.ServiceCenter.Redis;
using XXF.BaseService.ServiceCenter.SystemRuntime;
using XXF.ProjectTool;

namespace XXF.BaseService.ServiceCenter.Service.Provider
{
    /// <summary>
    /// 服务心跳守护
    /// </summary>
    public class ServiceHeatBeatProtect : IDisposable
    {
        //private static ServiceHeatBeatProtect serviceHeatBeatProtect = null;//单例实例

        private CancellationTokenSource cancelSource;
        private ServiceContext Context;
        private object _heartbeatrunlock = new object();//心跳运行锁,心跳任务不可并发执行
        private RedisNetCommandListener redislistener = null;
        private int heartbeatcount = 0;
        ////TODO 2015年10月27日 11:04:30 private ZK.ZKNodeRegister zkregister = null;
        public ServiceHeatBeatProtect(ServiceContext context)
        {
            try
            {
                Context = context;
                cancelSource = new CancellationTokenSource();
                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    HeartBeatRun();//开启心跳检查
                }, cancelSource.Token);

                redislistener = new RedisNetCommandListener(SystemConfigHelper.RedisServer); redislistener.Name = "服务" + Context.ServiceModel.servicename;
                redislistener.Register((channel, msg) =>
                {
                    RedisListenerCommand(channel, msg);
                }, cancelSource, SystemParamConfig.ServiceRedisChannel(Context.ServiceModel.id));

                ////TODO 2015年10月27日 11:04:30 zkregister = new ZK.ZKNodeRegister();
                ////TODO 2015年10月27日 11:04:30 zkregister.Register(cancelSource, Context.ServiceModel.id, Context.NodeModel.sessionid);
                LogHelper.Log(Context.ServiceModel.id, EnumLogType.Service, "服务心跳守护初始化成功");
            }
            catch (Exception exp)
            {
                LogHelper.Error(Context.ServiceModel.id, EnumLogType.Service, "服务心跳守护初始化失败", exp);
                throw exp;
            }
        }

        //心跳循环
        private void HeartBeatRun()
        {
            try
            {
                while (!cancelSource.IsCancellationRequested)
                {
                    HeartBeatTask();
                    System.Threading.Thread.Sleep(SystemParamConfig.Node_HeatBeat_Every_Time * 1000);
                    LogHelper.Debug(Context.ServiceModel.id, EnumLogType.Service, "心跳循环一轮完毕");
                }
            }
            catch (Exception exp)
            {
                if (!cancelSource.IsCancellationRequested)
                {
                    LogHelper.Error(Context.ServiceModel.id, EnumLogType.Service, "心跳循环出错", exp);
                }
            }
        }
        //心跳任务
        private void HeartBeatTask()
        {
            lock (_heartbeatrunlock)
            {
                try
                {
                    if (Context == null)
                    { }
                    //更新节点心跳
                    SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                    {
                        Dal.tb_node_dal nodedal = new Dal.tb_node_dal();
                        nodedal.UpdateLastUpdateTime(c, Context.NodeModel.sessionid);
                    });
                    if (Context.Performance != null)
                    {
                        Context.Performance.Collect();
                        //性能报表
                        SqlHelper.ExcuteSql(SystemConfigHelper.ReportConnectString, (c) =>
                       {
                           var reportdal = new Dal.tb_node_report_dal();
                           reportdal.Add(c, new Model.tb_node_report_model()
                           {
                               connectioncount = Context.Performance.ConnectionCount,
                               errorcount = Context.Performance.ErrorCount,
                               memorysize = Context.Performance.MemorySize,
                               nodeid = Context.NodeModel.id,
                               processcpuper = Context.Performance.ProcessCpuPercent,
                               processthreadcount = Context.Performance.ProcessThreadCount,
                               visitcount = Context.Performance.VisitCount
                           });
                       });
                        if (heartbeatcount % 2 == 0)
                        {
                            SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                               {
                                   Dal.tb_node_dal nodedal = new Dal.tb_node_dal();
                                   nodedal.UpdatePerformace(c, new Model.tb_node_model()
                                   {
                                       id = Context.NodeModel.id,
                                       serviceid = Context.NodeModel.serviceid,
                                       sessionid = Context.NodeModel.sessionid,
                                       runstate = (int)EnumRunState.Running,
                                       connectioncount = Context.Performance.ConnectionCount,
                                       errorcount = Context.Performance.ErrorCount,
                                       memorysize = Context.Performance.MemorySize,
                                       processcpuper = Context.Performance.ProcessCpuPercent,
                                       processthreadcount = Context.Performance.ProcessThreadCount,
                                       visitcount = Context.Performance.VisitCount,
                                       //filesize = CommonHelper.CurrentDirSize()


                                   });
                               });

                        }

                    }
                    heartbeatcount++;
                }
                catch (Exception exp)
                {
                    LogHelper.Error(Context.ServiceModel.id, EnumLogType.Service, "心跳任务出错", exp);
                }
            }

        }

        private void RedisListenerCommand(string channel, string msg)
        {
            try
            {
                if (!cancelSource.IsCancellationRequested)
                {
                    var command = new XXF.Serialization.JsonHelper().Deserialize<ServiceNetCommand>(msg);
                    if (command.ServiceNameSpace.ToLower() == Context.ServiceModel.servicenamespace.ToLower())
                    {
                        if (command.CommandType == EnumServiceCommandType.ServiceRestart || command.CommandType == EnumServiceCommandType.ServiceUpdate)
                        {
                            lock (_heartbeatrunlock)
                            {
                                //重启
                                Context.Server.Restart();
                            }
                        }
                    }
                }
                LogHelper.Debug(Context.ServiceModel.id, EnumLogType.Service, "Redis监听到消息:" + msg);
            }
            catch (Exception exp)
            {
                LogHelper.Error(Context.ServiceModel.id, EnumLogType.Service, "Redis监听出错", exp);
            }
        }

        public void Dispose()
        {
            if (redislistener != null)
                redislistener.Dispose();
            //if (zkregister != null)
            //    zkregister.Dispose();
            if (cancelSource != null)
                cancelSource.Cancel();

        }
    }
}
